package cn.net.isir.common.sms;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.qcloudsms.SmsMultiSender;
import com.github.qcloudsms.SmsMultiSenderResult;
import com.github.qcloudsms.SmsSingleSender;
import com.github.qcloudsms.SmsSingleSenderResult;
import com.github.qcloudsms.httpclient.HTTPException;
import com.github.qcloudsms.httpclient.HTTPResponse;
import cn.net.isir.common.config.SMSConfig;
import cn.net.isir.core.SpringApplicationContextUtils;
import cn.net.isir.entity.SmsLog;
import cn.net.isir.service.SmsLogService;
import cn.net.isir.utils.StringUtils;
import org.apache.log4j.Logger;
import org.json.JSONException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * 发送短信验证码的工具类
 */
public class SMSSender {

    // 日志工具类
    private static final Logger logger = Logger.getLogger(SMSSender.class);
    // 用户附加信息管理
    private static final SmsLogService smsLogService = SpringApplicationContextUtils.getBean("smsLogService", SmsLogService.class);


    /**
     * 发送单条短信
     *
     * @param tempId   模板id
     * @param phone    手机号
     * @param contents 模板内容
     * @return 结果
     */
    static SmsSingleSenderResult send(int tempId, String phone, String[] contents) {
        SmsSingleSenderResult result = null;
        try {
            SmsSingleSender ssender = new SmsSingleSender(SMSConfig.getAppid(), SMSConfig.getAppkey());

            //ext	否	string	用户的 session 内容，腾讯 server 回包中会原样返回，可选字段，不需要就填空
            //extend	否	string	短信码号扩展号，格式为纯数字串，其他格式无效。默认没有开通，开通请联系 腾讯云短信技术支持
            //params	是	array	模板参数，若模板没有参数，请提供为空数组
            //sig	是	string	App 凭证，具体计算方式见下注
            //sign	否	string	短信签名，如果使用默认签名，该字段可缺省
            //tel	是	object	国际电话号码，格式依据 e.164 标准为: +[国家码][手机号] ，示例如：+8613711112222， 其中前面有一个 + 符号 ，86 为国家码，13711112222 为手机号
            //time	是	number	请求发起时间，UNIX 时间戳（单位：秒），如果和系统时间相差超过 10 分钟则会返回失败
            //tpl_id	是	number	模板 ID，在控制台审核通过的模板 ID

            String sessionId = StringUtils.randomUUIDUpperCase();
            result = ssender.sendWithParam("86",//86 为国家码
                    phone,//13711112222
                    tempId,//模板 ID，在控制台审核通过的模板 ID
                    contents,//模板参数，若模板没有参数，请提供为空数组
                    "",//短信签名，如果使用默认签名，该字段可缺省
                    "",//短信码号扩展号，格式为纯数字串，其他格式无效。默认没有开通，开通请联系 腾讯云短信技术支持
                    sessionId);//用户的 session 内容，腾讯 server 回包中会原样返回，可选字段，不需要就填空
            logger.info(result);
            // 记录日志
            try {
                SmsLog log = new SmsLog();
                log.setSmsSupplier("腾讯云短信 SMS");
                log.setSmsSupplierSubCode(String.valueOf(SMSConfig.getAppid()));
                log.setSendPhone(phone);
                log.setSign("");
                log.setTempId(String.valueOf(tempId));
                log.setContents(JSON.toJSONString(contents));
                log.setSendTime(new Date());
                log.setSendResult(JSON.toJSONString(result));
                log.setSendFee(result.fee);
                log.setSessionId(sessionId);
                log.setIsMass(0);
                logger.info(log);
                smsLogService.insert(log);
            } catch (Exception ex) {
                ex.printStackTrace();
                logger.error(ex);
            }
            logger.info(result);
        } catch (HTTPException e) {
            // HTTP响应码错误
            e.printStackTrace();
        } catch (JSONException e) {
            // json解析错误
            e.printStackTrace();
        } catch (IOException e) {
            // 网络IO错误
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 发送多条短信
     *
     * @param tempId   模板id
     * @param phones   手机号
     * @param contents 模板内容
     * @return 结果
     */
    static SmsMultiSenderResult sends(int tempId, String[] phones, String[] contents) {
        if (phones == null || phones.length <= 0 || contents == null || contents.length <= 0) {
            return null;
        }
        SmsMultiSenderResult result = null;
        try {
            SmsMultiSender ssender = new SmsMultiSender(SMSConfig.getAppid(), SMSConfig.getAppkey());

            //ext	否	string	用户的 session 内容，腾讯 server 回包中会原样返回，可选字段，不需要就填空
            //extend	否	string	短信码号扩展号，格式为纯数字串，其他格式无效。默认没有开通，开通请联系 腾讯云短信技术支持
            //params	是	array	模板参数，若模板没有参数，请提供为空数组
            //sig	是	string	App 凭证，具体计算方式见下注
            //sign	否	string	短信签名，如果使用默认签名，该字段可缺省
            //tel	是	object	国际电话号码，格式依据 e.164 标准为: +[国家码][手机号] ，示例如：+8613711112222， 其中前面有一个 + 符号 ，86 为国家码，13711112222 为手机号
            //time	是	number	请求发起时间，UNIX 时间戳（单位：秒），如果和系统时间相差超过 10 分钟则会返回失败
            //tpl_id	是	number	模板 ID，在控制台审核通过的模板 ID

            String sessionId = StringUtils.randomUUIDUpperCase();
            result = ssender.sendWithParam("86",//86 为国家码
                    phones,//13711112222
                    tempId,//模板 ID，在控制台审核通过的模板 ID
                    contents,//模板参数，若模板没有参数，请提供为空数组
                    "",//短信签名，如果使用默认签名，该字段可缺省
                    "",//短信码号扩展号，格式为纯数字串，其他格式无效。默认没有开通，开通请联系 腾讯云短信技术支持
                    sessionId);//用户的 session 内容，腾讯 server 回包中会原样返回，可选字段，不需要就填空
            logger.info(result);
            logger.info("------------------=-=-=-=-==-==");
            logger.info(result.getResponse().body);
            logger.info("------------------=-=-=-=-==-==");

            // 记录日志
            try {
                SmsLog log = new SmsLog();
                log.setSmsSupplier("腾讯云短信 SMS");
                log.setSmsSupplierSubCode(String.valueOf(SMSConfig.getAppid()));
                log.setSendPhone(JSON.toJSONString(phones));
                log.setSign("");
                log.setTempId(String.valueOf(tempId));
                log.setContents(JSON.toJSONString(contents));
                log.setSendTime(new Date());
                log.setSendResult(JSON.toJSONString(result));
                int fee = 0;
                for (SmsMultiSenderResult.Detail detail : result.details) {
                    if (detail.result == 0 && "OK".equals(detail.errmsg)) {
                        fee += detail.fee;
                    }
                }
                log.setSendFee(fee);
                log.setSessionId(sessionId);
                log.setIsMass(0);
                logger.info(log);
                smsLogService.insert(log);
            } catch (Exception ex) {
                ex.printStackTrace();
                logger.error(ex);
            }
            logger.info(result);
        } catch (HTTPException e) {
            // HTTP响应码错误
            e.printStackTrace();
        } catch (JSONException e) {
            // json解析错误
            e.printStackTrace();
        } catch (IOException e) {
            // 网络IO错误
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 统一返回结果处理方法
     *
     * @param response 返回信息
     * @return 结果返回实体类，200表示全部发送，300表示部分发送失败，500表示全部发送失败
     */
    static SMSResult smsSenderResultHandle(String[] mobiles, HTTPResponse response) {
        logger.info("--------222222----------");
        logger.info(JSON.toJSONString(response.body));
        logger.info(response.body);
        JSONObject jo = JSONObject.parseObject(String.valueOf(response.body));
//        Resp resp = JSONObject.parseObject(String.valueOf(response.body), Resp.class);
        logger.info(jo);
        logger.info("--------222222----------");

        if (jo == null) {
            return new SMSResult(500, "未知错误，请检查参数并稍后再试", null);
        }
        //{"result":0,"errmsg":"OK","ext":"","sid":"8:awhkrQEMYcaNrdnvlVL20181220","fee":1}
        //{"result":0,"errmsg":"OK","ext":"","detail":[{"result":0,"errmsg":"OK","mobile":"15265201550","nationcode":"86","sid":"8:qa3nVb4Q3wn2elXRi6420181220","fee":1}]}

        //单发
        if (isBlank(jo.get("detail"))) {
            boolean successFlag = (int) jo.get("result") == 0 && jo.get("errmsg").equals("OK");

            SMSResult result = new SMSResult();
            result.setIsMass(0);
            result.setAllSendCount(mobiles.length);
            result.setAllSendMobiles(Arrays.asList(mobiles));
            result.setFailCount(successFlag ? 0 : mobiles.length);
            //如果发生错误，组织错误信息
            if (!successFlag) {
                FailMobileInfo info = new FailMobileInfo();
                info.setMobile(mobiles[0]);
                info.setFailCode(String.valueOf(jo.get("result")));
                info.setFailMsg(String.valueOf(jo.get("errmsg")));
                List<FailMobileInfo> failList = new ArrayList<>();
                failList.add(info);
                result.setFailMobiles(failList);
            }
            if (result.getFailCount() == 0) {
                result.setResult(200);
            } else {
                result.setResult(500);
            }
            logger.info(result);
            return result;
        }
        //群发
        if (!isBlank(jo.get("detail"))) {
            JSONArray jsonArray = JSONArray.parseArray(String.valueOf(jo.get("detail")));
            SMSResult result = new SMSResult();
            result.setIsMass(1);
            result.setAllSendCount(mobiles.length);
            result.setAllSendMobiles(Arrays.asList(mobiles));
            int failCount = 0;
            List<FailMobileInfo> failList = new ArrayList<>();
            for (Object o : jsonArray) {
                JSONObject jo2 = JSONObject.parseObject(JSON.toJSONString(o));
                boolean successFlag = (int) jo2.get("result") == 0 && jo2.get("errmsg").equals("OK");

                //如果发生错误，组织错误信息
                if (!successFlag) {
                    ++failCount;
                    FailMobileInfo info = new FailMobileInfo();
                    info.setMobile(String.valueOf(jo2.get("mobile")));
                    info.setFailCode(String.valueOf(jo2.get("result")));
                    info.setFailMsg(String.valueOf(jo2.get("errmsg")));
                    failList.add(info);
                }
            }
            result.setFailCount(failCount);
            result.setFailMobiles(failList);
            if (result.getFailCount() == 0) {
                result.setResult(200);
            }
            if (result.getFailCount() == result.getAllSendCount()) {
                result.setResult(500);
            }
            if (result.getFailCount() > 0 && result.getFailCount() < result.getAllSendCount()) {
                result.setResult(300);
            }
            logger.info(result);
            return result;
        }
        return null;
    }

    private static boolean isBlank(Object o) {
        if (o == null) {
            return true;
        }
        return StringUtils.isBlank(String.valueOf(o));
    }

}
